package com.example.sample.logic.fsm.base;

import android.util.SparseArray;

import java.util.List;

public abstract class FSMManager {

    private FSMState curState = null;
    private SparseArray<FSMState> stateMap = new SparseArray<>();
    private SparseArray<FSMEvt> evtMap = new SparseArray<>();

    public FSMManager(){
        init();
    }

    private void init(){
        // 初始化状态字典
        stateMap.clear();
        List<FSMState> stateList = getStateList();
        if (stateList != null && !stateList.isEmpty()){
            for (int i = 0; i<stateList.size(); i++){
                FSMState state = stateList.get(i);
                // 绑定manager到状态
                state.attachManager(this);
                int key = state.getStateValue();
                stateMap.append(key, state);
            }
        }

        // 初始化事件字典
        evtMap.clear();
        List<FSMEvt> evtList = getEvtList();
        if (evtList != null && !evtList.isEmpty()){
            for (int i = 0; i<evtList.size(); i++) {
                FSMEvt evt = evtList.get(0);
                int key = evt.getEvtValue();
                evtMap.append(key, evt);
            }
        }
    }

    /**
     * 本状态机涉及的状态，调用者来填充
     * 注意必须有状态值为0的状态，此状态作为入口状态
     */
    abstract protected List<FSMState> getStateList();

    /**
     * 本状态机涉及的事件，调用者填充
     */
    abstract protected List<FSMEvt> getEvtList();

    /**
     * 启动状态机。必须有状态值为0的状态
     */
    public void start(){
        changeState(0);
    }

    void changeState(int newState){
        FSMState state = stateMap.get(newState);
        if (state != null){
            this.curState = state;
            this.curState.onActive();
        }
    }

    /**
     * 外部事件通知状态机做出响应，主要是UI层调用
     * model层其实在状态内部去调用就好了
     */
    public void fireEvent(FSMEvt evt){
        if (curState != null){
            curState.handleEvt(evt);
        }
    }
}
